package heap;

import java.util.Arrays;
import java.util.Comparator;

/**
 *  扩容的事情就交给读者了!!
 *
 */
public class HeapQueue<E extends Comparable> {
    private E[] arr;
    private int size = 0;
    private int capacity = 0;
    Comparator<E> comparable; // 比较器!

    public HeapQueue() {
         capacity = 10;
        arr = (E[]) new Object[capacity];
    }

    public HeapQueue(int capacity) {
        this.capacity = capacity;
        arr = (E[]) new Object[capacity];
        size = 0;
    }

    public HeapQueue(int capacity, Comparator<E> comparable) {
        this.capacity = capacity;
        this.comparable = comparable;
        arr = (E[]) new Object[capacity];
        size = 0;
    }

    // 把数组直接建立成为一个堆
    public HeapQueue(E[] arr) {
        this.arr = arr;
        this.size = arr.length;
        this.capacity = arr.length;
        buildHeap(arr);
    }
    // 把数组直接建立成为一个堆
    public HeapQueue(E[] arr,Comparator<E> comparable) {
        this.arr = arr;
        this.size = arr.length;
        this.capacity = arr.length;
        this.comparable = comparable;
        buildHeap(arr);
    }


    private void buildHeap(E[] arr){
        // 将一个数组建立成一个堆!
        int child = (size - 2)/2; // 从下到上从右到左第一个非叶子节点开始依次向下调整!
        while(child >= 0){
            shiftDown(arr,child);
            child--;
        }
    }

    public void offer(E val){
        // 这里要有 扩容机制
        arr[size++] = val;
        shiftDown(arr,size - 1); // 向上调整!
    }

    public E poll() throws Exception {
        if(size < 1) throw new Exception("error : size = "+ size);
        E old = arr[0];
        arr[0] = arr[size - 1];
        size --;
        adjustDown(arr,0);
        return  old;
    }

    public E peek() throws Exception {
        if(size < 1) throw new Exception("error : size = "+ size);
        return arr[0];
    }
    // 向下调整!
    private void shiftDown(E[] heap,int index){
        if(comparable == null)  shiftDownWithNo(heap,index);
        else shiftDownWithOne(heap,index);
    }

    // 向上调整
    private void adjustDown(E[] heap,int index){
        if(comparable == null) adjustDownNo(heap,index);
        else adjustDownWithOne(heap,index);
    }

    private void adjustDownNo(E[] heap,int index){
        int cur = index;
        int parent = index;
        while(parent >= 0){
            parent = cur >> 1;
            if(arr[cur].compareTo(parent) >= 0){
                break;
            }
            swap(arr,cur,parent);
            cur = parent;
        }
    }

    private void adjustDownWithOne(E[] heap,int index){
        int cur = index;
        int parent = index;
        while(parent >= 0){
            parent = cur >> 1;
            if(comparable.compare(arr[cur],arr[parent]) >= 0){
                break;
            }
            swap(arr,cur,parent);
            cur = parent;
        }
    }


    // 未曾传入比较器
    private void shiftDownWithNo(E[] heap,int index){
            int cur = index;
            int leftChild = index * 2 + 1; // 左孩子位置!
            while(leftChild < size){
                if(leftChild+ 1 < size && heap[leftChild].compareTo(heap[leftChild+1]) > 0){
                    leftChild++;
                }
                if(heap[cur].compareTo(heap[leftChild]) <= 0){
                    break;
                }
                swap(heap,cur,leftChild);
                cur = leftChild;
                leftChild = leftChild * 2 + 1;
            }

    }
    // 传入比较器!
    private void shiftDownWithOne(E[] heap,int index){
        int cur = index;
        int leftChild = index * 2 + 1; // 左孩子位置!
        while(leftChild < size){
            if(leftChild+ 1 < size &&  comparable.compare(heap[leftChild],heap[leftChild+1]) > 0){
                leftChild++;
            }
            if(comparable.compare(heap[cur],heap[leftChild]) <= 0){
                break;
            }
            swap(heap,cur,leftChild);
            cur = leftChild;
            leftChild = leftChild * 2 + 1;
        }

    }

    private void swap(E[] arr,int i,int j){
        // 交换层面
        E e = arr[i];
        arr[i] = arr[j];
        arr[j] = e;
    }


    public int size(){
        return size;
    }

    public static void main(String[] args) {
        Integer[] arr =  {1,5,3,8,7,6};
       // HeapQueue<Integer> heap = new HeapQueue<>(arr,((o1, o2) -> o2 - o1));
        // todo:  报错类型没办法转换 ,我也是蒙蔽了!
        HeapQueue<Integer> integerHeapQueue = new HeapQueue<>(arr.length);
        //  heap.shiftDown(heap.arr,0);
        for (Integer val : arr ) {
            integerHeapQueue.offer(val);
        }
        System.out.println(Arrays.toString(arr));
    }
}
